package com.yzy.fly.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.yzy.fly.api.function.data.ValueDesensitizeFilter;
import com.yzy.fly.api.function.response.FlyResponseBodyHandler;
import com.yzy.fly.api.function.data.sensitive.handler.FlySensitiveHandler;
import com.yzy.fly.config.properties.CorsMappingConfig;
import com.yzy.fly.config.properties.FlyProperties;
import com.yzy.fly.util.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.*;

import java.util.ArrayList;
import java.util.List;

//@ConditionalOnMissingBean(name = {"webMvcConfig"})
@EnableConfigurationProperties({FlyProperties.class})
@Configuration
//@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private FlyProperties flyProperties;

    @Autowired(required = false)
    private List<FlySensitiveHandler> flySensitiveHandlers;

    @Autowired(required = false)
    private List<FlyResponseBodyHandler> flyResponseBodyHandlers;

    /**
     * 配置访问静态资源
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/image/**").addResourceLocations("classpath:/static/image/");
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }


    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//        converters.add(createGsonHttpMessageConverter());
        converters.add(0,createFastJsonHttpMessageConverter());
//        WebMvcConfigurer.super.configureMessageConverters(converters);
    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        if (CollectionUtils.isNotEmpty(flyResponseBodyHandlers)) {
            for (int i = 0; i < flyResponseBodyHandlers.size(); i++) {
                HandlerMethodReturnValueHandler handlerMethodReturnValueHandler = flyResponseBodyHandlers.get(i);
                returnValueHandlers.add(handlerMethodReturnValueHandler);
            }
        }
    }

    private FastJsonHttpMessageConverter createFastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter fastConverter = new FlyFastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //创建Fastjosn对象并设定序列化规则

        List<SerializerFeature> serializerFeatures = Lists.newArrayListWithCapacity(0);
//        serializerFeatures.add(SerializerFeature.PrettyFormat);
        serializerFeatures.add(SerializerFeature.WriteMapNullValue);
        serializerFeatures.add(SerializerFeature.WriteNullListAsEmpty);
        serializerFeatures.add(SerializerFeature.WriteDateUseDateFormat);
        // 配置序列化策略
//        serializerFeatures.add(SerializerFeature.BrowserCompatible);

        fastJsonConfig.setSerializerFeatures(serializerFeatures.toArray(new SerializerFeature[]{}));
        // 中文乱码解决方案
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON);//设定json格式且编码为UTF-8
        fastJsonConfig.setSerializeFilters(new ValueDesensitizeFilter(flySensitiveHandlers));//添加自己写的拦截器
        fastConverter.setSupportedMediaTypes(mediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);

//        if (value instanceof FastJsonContainer) {
//            FastJsonContainer fastJsonContainer = (FastJsonContainer) value;
//            PropertyPreFilters filters = fastJsonContainer.getFilters();
//            allFilters.addAll(filters.getFilters());
//            value = fastJsonContainer.getValue();
//        }

        return fastConverter;
    }

    private GsonHttpMessageConverter createGsonHttpMessageConverter() {
        Gson gson = new GsonBuilder()
                .setDateFormat(DateUtil.DateFormatPattern.yyyyMMddHHmmss)
                .create();
        GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter();
        gsonConverter.setGson(gson);
        return gsonConverter;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new MvcInterceptor());
//        registry.addInterceptor(this.antiReptileInterceptor).addPathPatterns("/**");
        //TODO 20221024
//        registry.addInterceptor(new AntiSpiderInterceptor()).addPathPatterns("/**");
//         super.addInterceptors(registry);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
//        registry.addMapping("/**")
//                .allowedOrigins("http://localhost:8080", "http://localhost:9527","http://localhost:3000", "http://10.10.10.232:8080", "http://10.10.10.169:8080")
//                .allowedMethods("PUT", "DELETE", "GET", "POST")
////                .allowedHeaders("header1", "header2", "header3")
////                .exposedHeaders("header1", "header2")
//                .allowCredentials(true).maxAge(3600);

        List<CorsMappingConfig> corsMappings = flyProperties.getConfiguration().getApi().getCorsMappings();
        if (CollectionUtils.isNotEmpty(corsMappings)) {
            for (int i = 0; i < corsMappings.size(); i++) {
                CorsMappingConfig corsMappingConfig = corsMappings.get(i);
                String pathPattern = corsMappingConfig.getPathPattern();
                if (StringUtils.isNotBlank(pathPattern)) {
                    boolean allowCredentials = corsMappingConfig.isAllowCredentials();
                    long maxAge = corsMappingConfig.getMaxAge();

                    CorsRegistration corsRegistration = registry.addMapping(pathPattern);
                    List<String> allowedOrigins = corsMappingConfig.getAllowedOrigins();
                    if (CollectionUtils.isNotEmpty(allowedOrigins)) {
                        corsRegistration.allowedOrigins(allowedOrigins.toArray(new String[]{}));
                    }

                    List<String> allowedMethods = corsMappingConfig.getAllowedMethods();
                    if (CollectionUtils.isNotEmpty(allowedMethods)) {
                        corsRegistration.allowedMethods(allowedMethods.toArray(new String[]{}));
                    }

                    List<String> allowedHeaders = corsMappingConfig.getAllowedHeaders();
                    if (CollectionUtils.isNotEmpty(allowedHeaders)) {
                        corsRegistration.allowedHeaders(allowedHeaders.toArray(new String[]{}));
                    }

                    List<String> exposedHeaders = corsMappingConfig.getExposedHeaders();
                    if (CollectionUtils.isNotEmpty(exposedHeaders)) {
                        corsRegistration.exposedHeaders(exposedHeaders.toArray(new String[]{}));
                    }

                    corsRegistration.allowCredentials(allowCredentials);
                    corsRegistration.maxAge(maxAge);
                }
            }
        }
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

